﻿// ===================================
// The use and distribution terms for this software are covered by the Microsoft public license, 
// visit for more info : http://qtest.codeplex.com 
// 
// You must not remove this copyright notice, or any other, from this software
// 
// Senthil Maruthaiappan  senips@gmail.com
// ===================================

using System;
using System.Collections.Generic;
using System.Text;
using QAPro.Test.FitServices.Interfaces;
using QAPro.Test.Interfaces;
using QAPro.Test.Library;
using WiseLight.Framework.Lite.Container;
using fit;
using fit.Service;
using fitSharp.Fit.Model;
using fitSharp.Fit.Service;
using fitSharp.Machine.Engine;
using fitSharp.Machine.Model;

namespace QAPro.Test.FitTestSystem
{
    [InstanceBehaviour(typeof (IFitTestEngine), InstanceBehaviourType.AlwaysCreate)]
    public class FitTestEngine : IFitTestEngine
    {
        private Memory _configuration;
        private IFitUtilService _fitUtilService;

        public IServices Services { get; set; }

        private IFitUtilService FitUtilityService
        {
            get { return _fitUtilService ?? (_fitUtilService = Services.Get<IFitUtilService>()); }
        }

        #region IFitTestEngine Members

        public NotifyErrors OnNotifyTestRunErrors { get; set; }

        public NotifyEventDelegate OnTestComplete { get; set; }

        public void Run(ITestNode node)
        {
            RunTest(node);
        }

        public void SetConfiguration(object configObj)
        {
            _configuration = configObj as Memory;
        }

        #endregion

        private void RunTest(ITestNode node)
        {
            if ((!node.IsRunnable) || ((node as IFitRunnableDoc) == null))
                return;
            node.TestResult.StartTime = DateTime.Now;
            IList<string> vars = new List<string>();

            if (_configuration == null)
            {
                FitUtilityService.GetVariables(node, ref vars);
                _configuration = new TypeDictionary();
                foreach (string asm in FitUtilityService.GetAsmPaths(vars))
                    _configuration.GetItem<ApplicationUnderTest>().AddAssembly(asm);
            }
            try
            {
                var service = new Service(_configuration);
                string document = (node as IFitRunnableDoc).GetTestDocument();
                Tree<Cell> result = service.Compose(new StoryTestString(document));
                Parse parse = result != null ? (Parse) result.Value : null;
                var writer = new TestEngineStoryTestWriter(service, node);

                var storyTest = new StoryTest(parse, writer);
                storyTest.ExecuteOnConfiguration(_configuration);
            }
            catch (Exception e)
            {
                string parentPath = string.Empty;
                TreeChildEnumerator.FindParentPath(node, ref parentPath);
                OnNotifyTestRunErrors(node.Name + " ( " + parentPath + " )\n\r" + e.Message + "\n\r" + e.StackTrace);
            }

            if (OnTestComplete != null)
                OnTestComplete(node);
        }

        #region Nested type: TestEngineStoryTestWriter

        private class TestEngineStoryTestWriter : StoryTestWriter
        {
            private readonly ITestNode _testNode;
            private readonly CellProcessor processor;

            private readonly StringBuilder sb = new StringBuilder();
            private bool _firstTable = true;
            private bool writesTables;

            public TestEngineStoryTestWriter(CellProcessor processor, ITestNode node)
            {
                this.processor = processor;
                _testNode = node;
                _testNode.TestResult.Exceptions = 0;
                _testNode.TestResult.Right = 0;
                _testNode.TestResult.Wrong = 0;
            }

            #region Implementation of StoryTestWriter

            public void WriteTable(Tree<Cell> table)
            {
                string tableResult = processor.ParseTree<Cell, StoryTableString>(table).ToString();
                if (string.IsNullOrEmpty(tableResult)) return;

                HandleTableResult(tableResult);
                writesTables = true;
            }

            public void WriteTest(Tree<Cell> test, TestCounts counts)
            {
                if (!writesTables)
                {
                    string testResult = processor.ParseTree<Cell, StoryTestString>(test).ToString();
                    if (!string.IsNullOrEmpty(testResult)) HandleTableResult(testResult);
                }

                _testNode.TestResult.Exceptions += counts.GetCount(TestStatus.Exception);
                _testNode.TestResult.Right += counts.GetCount(TestStatus.Right);
                ;
                _testNode.TestResult.Wrong += counts.GetCount(TestStatus.Wrong);
                ;
                _testNode.TestResult.EndTime = DateTime.Now;
            }

            private void HandleTableResult(string tableResult)
            {
                int startIdx = tableResult.IndexOf("{");
                int endIdx = tableResult.IndexOf("}");
                if ((startIdx == -1) || (endIdx == -1))
                    return;
                string testId = tableResult.Substring(startIdx + 1, endIdx - startIdx - 1);
                foreach (ITestNode node in _testNode.GetTreeChildEnumerator())
                {
                    if (node.ID.ToString().Equals(testId))
                    {
                        var fitResult = (node.TestResult as IFitResult);
                        fitResult.ResultText = tableResult.Replace("ID={" + testId + "}", "");
                        fitResult.EndTime = DateTime.Now;

                        fitResult.StartTime = _firstTable ? _testNode.TestResult.StartTime : DateTime.Now;
                    }
                }
                _firstTable = false;
            }

            #endregion
        }

        #endregion
    }
}